#include "nvic.h"
#include "nvic_hw.h"
#include "scb_hw.h"

void NVIC_SetPriorityGroup(NVIC_GroupEnum group)
{
	uint32_t val;

	switch (group) {
		case NVIC_GROUP_16:
			val = SCB_AIRCR_PRIGROUP_G16_S1 | SCB_AIRCR_VECTKEY;
			break;
		case NVIC_GROUP_8:
			val = SCB_AIRCR_PRIGROUP_G8_S2 | SCB_AIRCR_VECTKEY;
			break;
		case NVIC_GROUP_4:
			val = SCB_AIRCR_PRIGROUP_G4_S4 | SCB_AIRCR_VECTKEY;
			break;
		case NVIC_GROUP_2:
			val = SCB_AIRCR_PRIGROUP_G2_S8 | SCB_AIRCR_VECTKEY;
			break;
		case NVIC_GROUP_1:
			val = SCB_AIRCR_PRIGROUP_G1_S16 | SCB_AIRCR_VECTKEY;
			break;
		default:
			return;
	}

	SOC_SCB.AIRCR = val;
}

void NVIC_SetPriority(NVIC_IrqEnum irq, NVIC_PriorityEnum priority,
                      NVIC_PrioritySubEnum sub)
{
	uint8_t tmp1;

	/* 获取中断分组配置，根据中断分组计算优先级配置值 */
	switch (_SCB_GetPriorityGroup(SOC_SCB)) {
		case SCB_AIRCR_PRIGROUP_G16_S1:
			tmp1 = ((priority & 0xFU) << 4) | ((sub & 0x0U) << 4);
			break;
		case SCB_AIRCR_PRIGROUP_G8_S2:
			tmp1 = ((priority & 0x7U) << 5) | ((sub & 0x1U) << 4);
			break;
		case SCB_AIRCR_PRIGROUP_G4_S4:
			tmp1 = ((priority & 0x3U) << 6) | ((sub & 0x3U) << 4);
			break;
		case SCB_AIRCR_PRIGROUP_G2_S8:
			tmp1 = ((priority & 0x1U) << 7) | ((sub & 0x7U) << 4);
			break;
		case SCB_AIRCR_PRIGROUP_G1_S16:
			tmp1 = ((priority & 0x0U) << 0) | ((sub & 0xFU) << 4);
			break;
		default:
			return;
	}

	/* 根据irq编号，确定需要配置的寄存器 */
	if (irq >= 0) {
		SOC_NVIC.IP[irq] = tmp1;
	} else {
		SOC_SCB.SHP[(((uint32_t)irq) & 0xF)-4] = tmp1;
	}
}

void NVIC_EnableIrq(NVIC_IrqEnum irq)
{
	/* 仅外设中断需要使能 */
	if (irq >= 0) {
		/* 每个ISER寄存器32位，对应32个中断号 */
		SOC_NVIC.ISER[irq>>5] = 1UL << (irq & 0x1F);
	}
}

void NVIC_DisableIrq(NVIC_IrqEnum irq)
{
	/* 仅外设中断需要使能 */
	if (irq >= 0) {
		/* 每个ICER寄存器32位，对应32个中断号 */
		SOC_NVIC.ICER[irq>>5] = 1UL << (irq & 0x1F);
	}
}

/**
 * 即使中断未使能，外设或软件也可以挂起中断，等中断使能后会立即响应中断
 */
void NVIC_SetPendIrq(NVIC_IrqEnum irq)
{
	/* 仅外设中断可以挂起 */
	if (irq >= 0) {
		/* 每个ISPR寄存器32位，对应32个中断号 */
		SOC_NVIC.ISPR[irq>>5] = 1UL << (irq & 0x1F);
	}
}

void NVIC_ClearPendIrq(NVIC_IrqEnum irq)
{
	/* 仅外设中断可以挂起 */
	if (irq >= 0) {
		/* 每个ICPR寄存器32位，对应32个中断号 */
		SOC_NVIC.ICPR[irq>>5] = 1UL << (irq & 0x1F);
	}
}
